<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>学习 sentry 源码整体架构，打造属于自己的前端异常监控SDK | 若川的博客</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/favicon.ico">
    <link rel="mainfest" href="/mainfest.json">
    <meta name="description" content="若川，微信搜索「若川视野」关注我，长期交流学习。写有《学习源码整体架构系列》。包含jquery源码、underscore源码、lodash源码、sentry源码、vuex源码、axios源码、koa源码、redux源码。前端路上，PPT爱好者，所知甚少，唯善学。">
    
    <link rel="preload" href="/assets/css/0.styles.0ad39d54.css" as="style"><link rel="preload" href="/assets/js/app.9fbcafa6.js" as="script"><link rel="preload" href="/assets/js/2.33539d56.js" as="script"><link rel="preload" href="/assets/js/17.60b94fab.js" as="script"><link rel="preload" href="/assets/js/23.72249401.js" as="script"><link rel="prefetch" href="/assets/js/10.17a947d6.js"><link rel="prefetch" href="/assets/js/11.599e7eee.js"><link rel="prefetch" href="/assets/js/12.574e6f26.js"><link rel="prefetch" href="/assets/js/13.3a93edbc.js"><link rel="prefetch" href="/assets/js/14.c9f20b6b.js"><link rel="prefetch" href="/assets/js/15.c6b03e37.js"><link rel="prefetch" href="/assets/js/16.c445ccb9.js"><link rel="prefetch" href="/assets/js/18.86de3f95.js"><link rel="prefetch" href="/assets/js/19.6fedd448.js"><link rel="prefetch" href="/assets/js/20.5b11fd5b.js"><link rel="prefetch" href="/assets/js/21.e5faf0b7.js"><link rel="prefetch" href="/assets/js/22.23137eae.js"><link rel="prefetch" href="/assets/js/24.20d474b3.js"><link rel="prefetch" href="/assets/js/25.6dc03c07.js"><link rel="prefetch" href="/assets/js/26.fcf5232b.js"><link rel="prefetch" href="/assets/js/27.6ee352c4.js"><link rel="prefetch" href="/assets/js/28.7534ba1e.js"><link rel="prefetch" href="/assets/js/29.352ed61c.js"><link rel="prefetch" href="/assets/js/3.2f315ac7.js"><link rel="prefetch" href="/assets/js/30.e5dbb079.js"><link rel="prefetch" href="/assets/js/31.b8562982.js"><link rel="prefetch" href="/assets/js/32.f3c8f832.js"><link rel="prefetch" href="/assets/js/33.5ca5188e.js"><link rel="prefetch" href="/assets/js/34.624e3116.js"><link rel="prefetch" href="/assets/js/35.35a86a7c.js"><link rel="prefetch" href="/assets/js/36.21f88fe5.js"><link rel="prefetch" href="/assets/js/37.f5b01c2c.js"><link rel="prefetch" href="/assets/js/38.79ed2093.js"><link rel="prefetch" href="/assets/js/39.687f8425.js"><link rel="prefetch" href="/assets/js/4.9af06e45.js"><link rel="prefetch" href="/assets/js/40.deaa2213.js"><link rel="prefetch" href="/assets/js/41.ede9f8e5.js"><link rel="prefetch" href="/assets/js/42.c48ff846.js"><link rel="prefetch" href="/assets/js/43.012e8b81.js"><link rel="prefetch" href="/assets/js/44.d7040c40.js"><link rel="prefetch" href="/assets/js/45.2805a83b.js"><link rel="prefetch" href="/assets/js/46.95a37284.js"><link rel="prefetch" href="/assets/js/47.d1c213db.js"><link rel="prefetch" href="/assets/js/48.00be6d02.js"><link rel="prefetch" href="/assets/js/49.3d722bd1.js"><link rel="prefetch" href="/assets/js/5.aace9ee0.js"><link rel="prefetch" href="/assets/js/50.d9fa2cde.js"><link rel="prefetch" href="/assets/js/51.e0aaa97a.js"><link rel="prefetch" href="/assets/js/52.a700a7a9.js"><link rel="prefetch" href="/assets/js/53.dbb93ca1.js"><link rel="prefetch" href="/assets/js/6.e0576ee1.js"><link rel="prefetch" href="/assets/js/7.4a4a967d.js"><link rel="prefetch" href="/assets/js/8.b7698a4a.js"><link rel="prefetch" href="/assets/js/9.6930a420.js">
    <link rel="stylesheet" href="/assets/css/0.styles.0ad39d54.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><!----> <span class="site-name">若川的博客</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="https://image-static.segmentfault.com/355/182/3551821948-5df888aa1dc88_articlex" target="_blank" rel="noopener noreferrer" class="nav-link external">
  公众号：若川视野
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="/" class="nav-link">
  目录
</a></div><div class="nav-item"><a href="/about/" class="nav-link">
  关于我
</a></div><div class="nav-item"><a href="/poetry/2012-2016/" class="nav-link">
  曾经写的&quot;诗词&quot;
</a></div><div class="nav-item"><a href="https://github.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Github
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://juejin.im/user/1415826704971918/posts" target="_blank" rel="noopener noreferrer" class="nav-link external">
  掘金
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.zhihu.com/people/lxchuan12/activities" target="_blank" rel="noopener noreferrer" class="nav-link external">
  知乎
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.yuque.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  语雀
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其他" class="dropdown-title"><span class="title">其他</span> <span class="arrow down"></span></button> <button type="button" aria-label="其他" class="mobile-dropdown-title"><span class="title">其他</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://segmentfault.com/u/lxchuan12/articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  segmentFault
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://weibo.com/lxchuan12" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微博
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://www.jianshu.com/users/83129d433d72/latest_articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  简书
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="友链" class="dropdown-title"><span class="title">友链</span> <span class="arrow down"></span></button> <button type="button" aria-label="友链" class="mobile-dropdown-title"><span class="title">友链</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://shanyue.tech" target="_blank" rel="noopener noreferrer" class="nav-link external">
  山月
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://lucifer.ren" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lucifer
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://hungryturbo.com" target="_blank" rel="noopener noreferrer" class="nav-link external">
  童欧巴
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://www.scarsu.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  scarsu
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://mtc.nofwl.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lencx的博客
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://coder.itclan.cn/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  itclanCoder
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://ruizhengyun.cn" target="_blank" rel="noopener noreferrer" class="nav-link external">
  编程之上
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="https://image-static.segmentfault.com/355/182/3551821948-5df888aa1dc88_articlex" target="_blank" rel="noopener noreferrer" class="nav-link external">
  公众号：若川视野
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="/" class="nav-link">
  目录
</a></div><div class="nav-item"><a href="/about/" class="nav-link">
  关于我
</a></div><div class="nav-item"><a href="/poetry/2012-2016/" class="nav-link">
  曾经写的&quot;诗词&quot;
</a></div><div class="nav-item"><a href="https://github.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  Github
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://juejin.im/user/1415826704971918/posts" target="_blank" rel="noopener noreferrer" class="nav-link external">
  掘金
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.zhihu.com/people/lxchuan12/activities" target="_blank" rel="noopener noreferrer" class="nav-link external">
  知乎
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><a href="https://www.yuque.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer" class="nav-link external">
  语雀
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其他" class="dropdown-title"><span class="title">其他</span> <span class="arrow down"></span></button> <button type="button" aria-label="其他" class="mobile-dropdown-title"><span class="title">其他</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://segmentfault.com/u/lxchuan12/articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  segmentFault
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://weibo.com/lxchuan12" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微博
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://www.jianshu.com/users/83129d433d72/latest_articles" target="_blank" rel="noopener noreferrer" class="nav-link external">
  简书
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="友链" class="dropdown-title"><span class="title">友链</span> <span class="arrow down"></span></button> <button type="button" aria-label="友链" class="mobile-dropdown-title"><span class="title">友链</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="https://shanyue.tech" target="_blank" rel="noopener noreferrer" class="nav-link external">
  山月
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="http://lucifer.ren" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lucifer
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://hungryturbo.com" target="_blank" rel="noopener noreferrer" class="nav-link external">
  童欧巴
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://www.scarsu.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  scarsu
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://mtc.nofwl.com/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  lencx的博客
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://coder.itclan.cn/" target="_blank" rel="noopener noreferrer" class="nav-link external">
  itclanCoder
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li><li class="dropdown-item"><!----> <a href="https://ruizhengyun.cn" target="_blank" rel="noopener noreferrer" class="nav-link external">
  编程之上
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/" aria-current="page" class="sidebar-link">目录</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>学习源码系列</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/redux/" class="sidebar-link">学习 redux 源码整体架构，深入理解 redux 及其中间件原理</a></li><li><a href="/koa/" class="sidebar-link">学习 koa 源码的整体架构，浅析koa洋葱模型原理和co原理</a></li><li><a href="/axios/" class="sidebar-link">学习 axios 源码整体架构，打造属于自己的请求库</a></li><li><a href="/vuex/" class="sidebar-link">学习 vuex 源码整体架构，打造属于自己的状态管理库</a></li><li><a href="/sentry/" aria-current="page" class="active sidebar-link">学习 sentry 源码整体架构，打造属于自己的前端异常监控SDK</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_1-前言" class="sidebar-link">1. 前言</a></li><li class="sidebar-sub-header"><a href="/sentry/#_2-前端错误监控知识" class="sidebar-link">2. 前端错误监控知识</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_2-1-前端错误的分类" class="sidebar-link">2.1 前端错误的分类</a></li><li class="sidebar-sub-header"><a href="/sentry/#_2-2-error事件捕获代码示例" class="sidebar-link">2.2 Error事件捕获代码示例</a></li><li class="sidebar-sub-header"><a href="/sentry/#_2-3-上报错误的基本原理" class="sidebar-link">2.3 上报错误的基本原理</a></li></ul></li><li class="sidebar-sub-header"><a href="/sentry/#_3-sentry-前端异常监控基本原理" class="sidebar-link">3. Sentry 前端异常监控基本原理</a></li><li class="sidebar-sub-header"><a href="/sentry/#_4-sentry-源码入口和出口" class="sidebar-link">4. Sentry 源码入口和出口</a></li><li class="sidebar-sub-header"><a href="/sentry/#_5-sentry-init-初始化-之-init-函数" class="sidebar-link">5. Sentry.init 初始化 之 init 函数</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_5-1-getglobalobject、innodeenv-函数" class="sidebar-link">5.1 getGlobalObject、inNodeEnv 函数</a></li></ul></li><li class="sidebar-sub-header"><a href="/sentry/#_6-initandbind-函数之-new-browserclient-options" class="sidebar-link">6. initAndBind 函数之 new BrowserClient(options)</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_6-1-browserclient-构造函数" class="sidebar-link">6.1 BrowserClient 构造函数</a></li><li class="sidebar-sub-header"><a href="/sentry/#_6-2-extends、extendstatics-打包代码实现的继承" class="sidebar-link">6.2 __extends、extendStatics 打包代码实现的继承</a></li><li class="sidebar-sub-header"><a href="/sentry/#_6-3-browserbackend-构造函数-浏览器后端" class="sidebar-link">6.3 BrowserBackend  构造函数 （浏览器后端）</a></li><li class="sidebar-sub-header"><a href="/sentry/#_6-4-小结1-new-browerclient-经过一系列的继承和初始化" class="sidebar-link">6.4 小结1. new BrowerClient 经过一系列的继承和初始化</a></li></ul></li><li class="sidebar-sub-header"><a href="/sentry/#_7-initandbind-函数之-getcurrenthub-bindclient" class="sidebar-link">7. initAndBind 函数之 getCurrentHub().bindClient()</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_7-1-getcurrenthub-函数" class="sidebar-link">7.1 getCurrentHub 函数</a></li><li class="sidebar-sub-header"><a href="/sentry/#_7-2-衍生的函数-getmaincarrier、gethubfromcarrier" class="sidebar-link">7.2 衍生的函数 getMainCarrier、getHubFromCarrier</a></li><li class="sidebar-sub-header"><a href="/sentry/#_7-3-bindclient-绑定客户端在当前控制中心上" class="sidebar-link">7.3 bindClient 绑定客户端在当前控制中心上</a></li><li class="sidebar-sub-header"><a href="/sentry/#_7-4-小结2-经过一系列的继承和初始化" class="sidebar-link">7.4 小结2. 经过一系列的继承和初始化</a></li></ul></li><li class="sidebar-sub-header"><a href="/sentry/#_8-capturemessage-函数" class="sidebar-link">8. captureMessage 函数</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_8-1-fetchtransport-prototype-sendevent" class="sidebar-link">8.1 FetchTransport.prototype.sendEvent</a></li></ul></li><li class="sidebar-sub-header"><a href="/sentry/#_9-window-onerror-和-window-onunhandledrejection-捕获-错误" class="sidebar-link">9. window.onerror 和 window.onunhandledrejection 捕获 错误</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/sentry/#_9-1-captureevent" class="sidebar-link">9.1 captureEvent</a></li></ul></li><li class="sidebar-sub-header"><a href="/sentry/#_10-总结" class="sidebar-link">10. 总结</a></li><li class="sidebar-sub-header"><a href="/sentry/#_11-推荐阅读" class="sidebar-link">11. 推荐阅读</a></li><li class="sidebar-sub-header"><a href="/sentry/#笔者往期文章" class="sidebar-link">笔者往期文章</a></li><li class="sidebar-sub-header"><a href="/sentry/#关于" class="sidebar-link">关于</a></li><li class="sidebar-sub-header"><a href="/sentry/#微信公众号-若川视野" class="sidebar-link">微信公众号  若川视野</a></li></ul></li><li><a href="/lodash/" class="sidebar-link">学习 lodash  源码整体架构，打造属于自己的函数式编程类库</a></li><li><a href="/underscore/" class="sidebar-link">学习underscore源码整体架构，打造属于自己的函数式编程类库</a></li><li><a href="/jquery/" class="sidebar-link">学习 jQuery 源码整体架构，打造属于自己的 js 类库</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>面试官问系列</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>历史文章</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>杂文</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>曾经写的&quot;诗词&quot;</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>年度总结</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>关于</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="学习-sentry-源码整体架构-打造属于自己的前端异常监控sdk"><a href="#学习-sentry-源码整体架构-打造属于自己的前端异常监控sdk" class="header-anchor">#</a> 学习 sentry 源码整体架构，打造属于自己的前端异常监控SDK</h1> <h2 id="_1-前言"><a href="#_1-前言" class="header-anchor">#</a> 1. 前言</h2> <blockquote><p>你好，我是<a href="https://lxchuan12.gitee.io" target="_blank" rel="noopener noreferrer">若川<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，微信搜索<a href="https://mp.weixin.qq.com/s/c3hFML3XN9KCUetDOZd-DQ" target="_blank" rel="noopener noreferrer">「若川视野」<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>关注我，专注前端技术分享。欢迎加我微信<code>ruochuan12</code>，加群交流学习。</p></blockquote> <blockquote><p>这是<code>学习源码整体架构系列</code>第四篇。整体架构这词语好像有点大，姑且就算是源码整体结构吧，主要就是学习是代码整体结构，不深究其他不是主线的具体函数的实现。文章学习的是打包整合后的代码，不是实际仓库中的拆分的代码。</p></blockquote> <blockquote><p><a href="https://github.com/lxchuan12/sentry-analysis.git" target="_blank" rel="noopener noreferrer">本文仓库地址<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>：<code>git clone https://github.com/lxchuan12/sentry-analysis.git</code></p></blockquote> <blockquote><p><strong>要是有人说到怎么读源码，正在读文章的你能推荐我的源码系列文章，那真是太好了</strong>。</p></blockquote> <p><code>学习源码整体架构系列</code>文章如下：</p> <blockquote><p>1.<a href="https://juejin.im/post/5d39d2cbf265da1bc23fbd42" target="_blank" rel="noopener noreferrer">学习 jQuery 源码整体架构，打造属于自己的 js 类库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
2.<a href="https://juejin.im/post/5d4bf94de51d453bb13b65dc" target="_blank" rel="noopener noreferrer">学习 underscore 源码整体架构，打造属于自己的函数式编程类库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
3.<a href="https://juejin.im/post/5d767e1d6fb9a06b032025ea" target="_blank" rel="noopener noreferrer">学习 lodash 源码整体架构，打造属于自己的函数式编程类库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
4.<a href="https://juejin.im/post/5dba5a39e51d452a2378348a" target="_blank" rel="noopener noreferrer">学习 sentry 源码整体架构，打造属于自己的前端异常监控SDK<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
5.<a href="https://juejin.im/post/5dd4e61a6fb9a05a5c010af0" target="_blank" rel="noopener noreferrer">学习 vuex 源码整体架构，打造属于自己的状态管理库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
6.<a href="https://juejin.im/post/5df349b5518825123751ba66" target="_blank" rel="noopener noreferrer">学习 axios 源码整体架构，打造属于自己的请求库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
7.<a href="https://juejin.im/post/5e69925cf265da571e262fe6" target="_blank" rel="noopener noreferrer">学习 koa 源码的整体架构，浅析koa洋葱模型原理和co原理<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
8.<a href="https://juejin.im/post/5ee63b7d51882542fc6265ad" target="_blank" rel="noopener noreferrer">学习 redux 源码整体架构，深入理解 redux 及其中间件原理<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>感兴趣的读者可以点击阅读。<br>
其他源码计划中的有：<a href="https://github.com/lxchuan12/express-analysis" target="_blank" rel="noopener noreferrer"><code>express</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>、<a href="https://github.com/lxchuan12/vue-router-analysis" target="_blank" rel="noopener noreferrer"><code>vue-rotuer</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>、<a href="https://github.com/lxchuan12/react-redux-analysis" target="_blank" rel="noopener noreferrer"><code>react-redux</code><span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 等源码，不知何时能写完（哭泣），欢迎持续关注我（若川）。</p> <p>源码类文章，一般阅读量不高。已经有能力看懂的，自己就看了。不想看，不敢看的就不会去看源码。<br>
所以我的文章，尽量写得让想看源码又不知道怎么看的读者能看懂。</p> <p><strong>导读</strong><br>
本文通过梳理前端错误监控知识、介绍<code>sentry</code>错误监控原理、<code>sentry</code>初始化、<code>Ajax</code>上报、<code>window.onerror、window.onunhandledrejection</code>几个方面来学习<code>sentry</code>的源码。</p> <p>开发微信小程序，想着搭建小程序错误监控方案。最近用了丁香园 开源的<code>Sentry</code> 小程序 <code>SDK</code><a href="https://github.com/lizhiyao/sentry-miniapp" target="_blank" rel="noopener noreferrer">sentry-miniapp<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>。
顺便研究下<a href="https://github.com/getsentry/sentry-javascript" target="_blank" rel="noopener noreferrer"><code>sentry-javascript</code>仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 的源码整体架构，于是有了这篇文章。</p> <p>本文分析的是打包后未压缩的源码，源码总行数五千余行，链接地址是：<a href="https://browser.sentry-cdn.com/5.7.1/bundle.js" target="_blank" rel="noopener noreferrer">https://browser.sentry-cdn.com/5.7.1/bundle.js<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>， 版本是<code>v5.7.1</code>。</p> <p>本文示例等源代码在这我的<code>github</code>博客中<a href="https://github.com/lxchuan12/blog/blob/master/docs/sentry/README.md" target="_blank" rel="noopener noreferrer">github blog sentry<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，需要的读者可以点击查看，如果觉得不错，可以顺便<code>star</code>一下。</p> <p>看源码前先来梳理下前端错误监控的知识。</p> <h2 id="_2-前端错误监控知识"><a href="#_2-前端错误监控知识" class="header-anchor">#</a> 2. 前端错误监控知识</h2> <p>摘抄自 <a href="https://coding.imooc.com/class/129.html" target="_blank" rel="noopener noreferrer">慕课网视频教程：前端跳槽面试必备技巧<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://articles.jerryshi.com/learning/fe/js-interview-skill.html#_4-4-%E9%94%99%E8%AF%AF%E7%9B%91%E6%8E%A7%E7%B1%BB" target="_blank" rel="noopener noreferrer">别人做的笔记：前端跳槽面试必备技巧-4-4 错误监控类<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h3 id="_2-1-前端错误的分类"><a href="#_2-1-前端错误的分类" class="header-anchor">#</a> 2.1 前端错误的分类</h3> <blockquote><p><strong>1.即时运行错误：代码错误</strong></p></blockquote> <p><code>try...catch</code></p> <p><code>window.onerror</code> (也可以用<code>DOM2</code>事件监听)</p> <blockquote><p><strong>2.资源加载错误</strong></p></blockquote> <p><code>object.onerror</code>: <code>dom</code>对象的<code>onerror</code>事件</p> <p><code>performance.getEntries()</code></p> <p><code>Error</code>事件捕获</p> <blockquote><p>3.<strong>使用<code>performance.getEntries()</code>获取网页图片加载错误</strong></p></blockquote> <p><code>var allImgs = document.getElementsByTagName('image')</code></p> <p><code>var loadedImgs = performance.getEntries().filter(i =&gt; i.initiatorType === 'img')</code></p> <p>最后<code>allIms</code>和<code>loadedImgs</code>对比即可找出图片资源未加载项目</p> <h3 id="_2-2-error事件捕获代码示例"><a href="#_2-2-error事件捕获代码示例" class="header-anchor">#</a> 2.2 Error事件捕获代码示例</h3> <div class="language-js extra-class"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'error'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'捕获'</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token comment">// 这里只有捕获才能触发事件，冒泡是不能触发</span>
</code></pre></div><h3 id="_2-3-上报错误的基本原理"><a href="#_2-3-上报错误的基本原理" class="header-anchor">#</a> 2.3 上报错误的基本原理</h3> <p>1.采用<code>Ajax</code>通信的方式上报</p> <p>2.利用<code>Image</code>对象上报 (主流方式)</p> <p><code>Image</code>上报错误方式：
<code>(new Image()).src = 'https://lxchuan12.cn/error?name=若川'</code></p> <h2 id="_3-sentry-前端异常监控基本原理"><a href="#_3-sentry-前端异常监控基本原理" class="header-anchor">#</a> 3. Sentry 前端异常监控基本原理</h2> <blockquote><p>1.重写 <code>window.onerror</code> 方法、重写 <code>window.onunhandledrejection</code> 方法</p></blockquote> <p>如果不了解<code>onerror和onunhandledrejection</code>方法的读者，可以看相关的<code>MDN</code>文档。这里简要介绍一下：</p> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/GlobalEventHandlers/onerror" target="_blank" rel="noopener noreferrer">MDN GlobalEventHandlers.onerror<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <div class="language-js extra-class"><pre class="language-js"><code>window<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> source<span class="token punctuation">,</span> lineno<span class="token punctuation">,</span> colno<span class="token punctuation">,</span> error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'message, source, lineno, colno, error'</span><span class="token punctuation">,</span> message<span class="token punctuation">,</span> source<span class="token punctuation">,</span> lineno<span class="token punctuation">,</span> colno<span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><blockquote><p>参数：<br> <code>message</code>：错误信息（字符串）。可用于<code>HTML onerror=&quot;&quot;</code>处理程序中的<code>event</code>。<br> <code>source</code>：发生错误的脚本<code>URL</code>（字符串）<br> <code>lineno</code>：发生错误的行号（数字）<br> <code>colno</code>：发生错误的列号（数字）<br> <code>error</code>：<code>Error</code>对象（对象）<br></p></blockquote> <p><a href="https://developer.mozilla.org/zh-CN/docs/Web/Events/unhandledrejection" target="_blank" rel="noopener noreferrer">MDN unhandledrejection<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <blockquote><p>当 <code>Promise</code> 被 <code>reject</code> 且没有 <code>reject</code> 处理器的时候，会触发 <code>unhandledrejection</code> 事件；这可能发生在 <code>window</code> 下，但也可能发生在 <code>Worker</code> 中。 这对于调试回退错误处理非常有用。</p></blockquote> <p><code>Sentry</code> 源码可以搜索 <code>global.onerror</code> 定位到具体位置</p> <div class="language-js extra-class"><pre class="language-js"><code> <span class="token class-name">GlobalHandlers</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_installGlobalOnErrorHandler</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 代码有删减</span>
	<span class="token comment">// 这里的 this._global 在浏览器中就是 window</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_oldOnErrorHandler <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span>onerror<span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">msg<span class="token punctuation">,</span> url<span class="token punctuation">,</span> line<span class="token punctuation">,</span> column<span class="token punctuation">,</span> error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
	<span class="token comment">// code ...</span>
 <span class="token punctuation">}</span>
</code></pre></div><p>同样，可以搜索<code>global.onunhandledrejection</code> 定位到具体位置</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">GlobalHandlers</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_installGlobalOnUnhandledRejectionHandler</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 代码有删减</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_oldOnUnhandledRejectionHandler <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span>onunhandledrejection<span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span><span class="token function-variable function">onunhandledrejection</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><blockquote><p>2.采用<code>Ajax</code>上传</p></blockquote> <p>支持 <code>fetch</code> 使用 <code>fetch</code>，否则使用　<code>XHR</code>。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">BrowserBackend</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_setupTransport</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 代码有删减</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">supportsFetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">FetchTransport</span><span class="token punctuation">(</span>transportOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">XHRTransport</span><span class="token punctuation">(</span>transportOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><blockquote><p>2.1 <code>fetch</code></p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">FetchTransport</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">sendEvent</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> defaultOptions <span class="token operator">=</span> <span class="token punctuation">{</span>
		body<span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">,</span>
		method<span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span>
		referrerPolicy<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token function">supportsReferrerPolicy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'origin'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_buffer<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>global$<span class="token number">2.</span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>url<span class="token punctuation">,</span> defaultOptions<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
		status<span class="token operator">:</span> exports<span class="token punctuation">.</span>Status<span class="token punctuation">.</span><span class="token function">fromHttpCode</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>status<span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><blockquote><p>2.2 <code>XMLHttpRequest</code></p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">XHRTransport</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">sendEvent</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> _this <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_buffer<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SyncPromise</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">resolve<span class="token punctuation">,</span> reject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token comment">// 熟悉的 XMLHttpRequest</span>
		<span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		request<span class="token punctuation">.</span><span class="token function-variable function">onreadystatechange</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span>readyState <span class="token operator">!==</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token keyword">return</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
			<span class="token keyword">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
				<span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
					status<span class="token operator">:</span> exports<span class="token punctuation">.</span>Status<span class="token punctuation">.</span><span class="token function">fromHttpCode</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span>status<span class="token punctuation">)</span><span class="token punctuation">,</span>
				<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
			<span class="token function">reject</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span><span class="token punctuation">;</span>
		request<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">'POST'</span><span class="token punctuation">,</span> _this<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span>
		request<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>接下来主要通过Sentry初始化、如何<code>Ajax上报</code>和<code>window.onerror、window.onunhandledrejection</code>三条主线来学习源码。</p> <blockquote><p>如果看到这里，暂时不想关注后面的源码细节，直接看后文小结1和2的两张图。或者可以点赞或收藏这篇文章，后续想看了再看。</p></blockquote> <h2 id="_4-sentry-源码入口和出口"><a href="#_4-sentry-源码入口和出口" class="header-anchor">#</a> 4. Sentry 源码入口和出口</h2> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> Sentry <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">exports</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
	<span class="token comment">// code ...</span>

    <span class="token keyword">var</span> <span class="token constant">SDK_NAME</span> <span class="token operator">=</span> <span class="token string">'sentry.javascript.browser'</span><span class="token punctuation">;</span>
	<span class="token keyword">var</span> <span class="token constant">SDK_VERSION</span> <span class="token operator">=</span> <span class="token string">'5.7.1'</span><span class="token punctuation">;</span>

	<span class="token comment">// code ...</span>
	<span class="token comment">// 省略了导出的Sentry的若干个方法和属性</span>
	<span class="token comment">// 只列出了如下几个</span>
    exports<span class="token punctuation">.</span><span class="token constant">SDK_NAME</span> <span class="token operator">=</span> <span class="token constant">SDK_NAME</span><span class="token punctuation">;</span>
    exports<span class="token punctuation">.</span><span class="token constant">SDK_VERSION</span> <span class="token operator">=</span> <span class="token constant">SDK_VERSION</span><span class="token punctuation">;</span>
	<span class="token comment">// 重点关注 captureMessage</span>
    exports<span class="token punctuation">.</span>captureMessage <span class="token operator">=</span> captureMessage<span class="token punctuation">;</span>
	<span class="token comment">// 重点关注 init</span>
    exports<span class="token punctuation">.</span>init <span class="token operator">=</span> init<span class="token punctuation">;</span>

    <span class="token keyword">return</span> exports<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="_5-sentry-init-初始化-之-init-函数"><a href="#_5-sentry-init-初始化-之-init-函数" class="header-anchor">#</a> 5. Sentry.init 初始化 之 init 函数</h2> <p>初始化</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 这里的dsn，是sentry.io网站会生成的。</span>
Sentry<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">{</span> dsn<span class="token operator">:</span> <span class="token string">'xxx'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// options 是 {dsn: '...'}</span>
<span class="token keyword">function</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 如果options 是undefined，则赋值为 空对象</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options <span class="token operator">===</span> <span class="token keyword">void</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
	<span class="token comment">// 如果没传 defaultIntegrations 则赋值默认的</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>defaultIntegrations <span class="token operator">===</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		options<span class="token punctuation">.</span>defaultIntegrations <span class="token operator">=</span> defaultIntegrations<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 初始化语句</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>release <span class="token operator">===</span> <span class="token keyword">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">var</span> window_1 <span class="token operator">=</span> <span class="token function">getGlobalObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">// 这是给  sentry-webpack-plugin 插件提供的，webpack插件注入的变量。这里没用这个插件，所以这里不深究。</span>
		<span class="token comment">// This supports the variable that sentry-webpack-plugin injects</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>window_1<span class="token punctuation">.</span><span class="token constant">SENTRY_RELEASE</span> <span class="token operator">&amp;&amp;</span> window_1<span class="token punctuation">.</span><span class="token constant">SENTRY_RELEASE</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			options<span class="token punctuation">.</span>release <span class="token operator">=</span> window_1<span class="token punctuation">.</span><span class="token constant">SENTRY_RELEASE</span><span class="token punctuation">.</span>id<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 初始化并且绑定</span>
	<span class="token function">initAndBind</span><span class="token punctuation">(</span>BrowserClient<span class="token punctuation">,</span> options<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="_5-1-getglobalobject、innodeenv-函数"><a href="#_5-1-getglobalobject、innodeenv-函数" class="header-anchor">#</a> 5.1 getGlobalObject、inNodeEnv 函数</h3> <p>很多地方用到这个函数<code>getGlobalObject</code>。其实做的事情也比较简单，就是获取全局对象。浏览器中是<code>window</code>。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * 判断是否是node环境
 * Checks whether we're in the Node.js or Browser environment
 *
 * @returns Answer to given question
 */</span>
<span class="token keyword">function</span> <span class="token function">isNodeEnv</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// tslint:disable:strict-type-predicates</span>
	<span class="token keyword">return</span> <span class="token class-name">Object</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">typeof</span> process <span class="token operator">!==</span> <span class="token string">'undefined'</span> <span class="token operator">?</span> process <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token string">'[object process]'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">var</span> fallbackGlobalObject <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token comment">/**
 * Safely get global scope object
 *
 * @returns Global scope object
 */</span>
<span class="token keyword">function</span> <span class="token function">getGlobalObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token function">isNodeEnv</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
	<span class="token comment">// 是 node 环境 赋值给 global</span>
		<span class="token operator">?</span> global
		<span class="token operator">:</span> <span class="token keyword">typeof</span> window <span class="token operator">!==</span> <span class="token string">'undefined'</span>
			<span class="token operator">?</span> window
			<span class="token comment">// 不是 window self 不是undefined 说明是 Web Worker 环境</span>
			<span class="token operator">:</span> <span class="token keyword">typeof</span> self <span class="token operator">!==</span> <span class="token string">'undefined'</span>
				<span class="token operator">?</span> self
				<span class="token comment">// 都不是，赋值给空对象。</span>
				<span class="token operator">:</span> fallbackGlobalObject<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>继续看 <code>initAndBind</code> 函数</p> <h2 id="_6-initandbind-函数之-new-browserclient-options"><a href="#_6-initandbind-函数之-new-browserclient-options" class="header-anchor">#</a> 6. initAndBind 函数之 new BrowserClient(options)</h2> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">initAndBind</span><span class="token punctuation">(</span><span class="token parameter">clientClass<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 这里没有开启debug模式，logger.enable() 这句不会执行</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>debug <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		logger<span class="token punctuation">.</span><span class="token function">enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">bindClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">clientClass</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>可以看出 <code>initAndBind()</code>，第一个参数是 <code>BrowserClient</code> 构造函数，第二个参数是初始化后的<code>options</code>。
接着先看 构造函数 <code>BrowserClient</code>。
另一条线 <code>getCurrentHub().bindClient()</code> 先不看。</p> <h3 id="_6-1-browserclient-构造函数"><a href="#_6-1-browserclient-构造函数" class="header-anchor">#</a> 6.1 BrowserClient 构造函数</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> BrowserClient <span class="token operator">=</span> <span class="token comment">/** @class */</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">_super</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// `BrowserClient` 继承自`BaseClient`</span>
	<span class="token function">__extends</span><span class="token punctuation">(</span>BrowserClient<span class="token punctuation">,</span> _super<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">/**
	 * Creates a new Browser SDK instance.
	 *
	 * @param options Configuration options for this SDK.
	 */</span>
	<span class="token keyword">function</span> <span class="token function">BrowserClient</span><span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>options <span class="token operator">===</span> <span class="token keyword">void</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> options <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
		<span class="token comment">// 把`BrowserBackend`，`options`传参给`BaseClient`调用。</span>
		<span class="token keyword">return</span> <span class="token function">_super</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> BrowserBackend<span class="token punctuation">,</span> options<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">return</span> BrowserClient<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">(</span>BaseClient<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><code>从代码中可以看出</code>：
<code>BrowserClient</code> 继承自<code>BaseClient</code>，并且把<code>BrowserBackend</code>，<code>options</code>传参给<code>BaseClient</code>调用。</p> <p>先看 <code>BrowserBackend</code>，这里的<code>BaseClient</code>，暂时不看。</p> <p>看<code>BrowserBackend</code>之前，先提一下继承、继承静态属性和方法。</p> <h3 id="_6-2-extends、extendstatics-打包代码实现的继承"><a href="#_6-2-extends、extendstatics-打包代码实现的继承" class="header-anchor">#</a> 6.2 __extends、extendStatics 打包代码实现的继承</h3> <p>未打包的源码是使用<code>ES6 extends</code>实现的。这是打包后的对<code>ES6</code>的<code>extends</code>的一种实现。</p> <p>如果对继承还不是很熟悉的读者，可以参考我之前写的文章。<a href="https://juejin.im/post/5c433e216fb9a049c15f841b" target="_blank" rel="noopener noreferrer">面试官问：JS的继承<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 继承静态方法和属性</span>
<span class="token keyword">var</span> <span class="token function-variable function">extendStatics</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">d<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 如果支持 Object.setPrototypeOf 这个函数，直接使用</span>
	<span class="token comment">// 不支持，则使用原型__proto__ 属性，</span>
	<span class="token comment">// 如何还不支持（但有可能__proto__也不支持，毕竟是浏览器特有的方法。）</span>
	<span class="token comment">// 则使用for in 遍历原型链上的属性，从而达到继承的目的。</span>
	extendStatics <span class="token operator">=</span> Object<span class="token punctuation">.</span>setPrototypeOf <span class="token operator">||</span>
		<span class="token punctuation">(</span><span class="token punctuation">{</span> __proto__<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token keyword">instanceof</span> <span class="token class-name">Array</span> <span class="token operator">&amp;&amp;</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">d<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> d<span class="token punctuation">.</span>__proto__ <span class="token operator">=</span> b<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">||</span>
		<span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">d<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> p <span class="token keyword">in</span> b<span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>b<span class="token punctuation">.</span><span class="token function">hasOwnProperty</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">)</span> d<span class="token punctuation">[</span>p<span class="token punctuation">]</span> <span class="token operator">=</span> b<span class="token punctuation">[</span>p<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> <span class="token function">extendStatics</span><span class="token punctuation">(</span>d<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">__extends</span><span class="token punctuation">(</span><span class="token parameter">d<span class="token punctuation">,</span> b</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token function">extendStatics</span><span class="token punctuation">(</span>d<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 申明构造函数__ 并且把 d 赋值给 constructor</span>
	<span class="token keyword">function</span> <span class="token function">__</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>constructor <span class="token operator">=</span> d<span class="token punctuation">;</span> <span class="token punctuation">}</span>
	<span class="token comment">// (__.prototype = b.prototype, new __()) 这种逗号形式的代码，最终返回是后者，也就是 new __()</span>
	<span class="token comment">// 比如 (typeof null, 1) 返回的是1</span>
	<span class="token comment">// 如果 b === null 用Object.create(b) 创建 ，也就是一个不含原型链等信息的空对象 {}</span>
	<span class="token comment">// 否则使用 new __() 返回</span>
	d<span class="token punctuation">.</span>prototype <span class="token operator">=</span> b <span class="token operator">===</span> <span class="token keyword">null</span> <span class="token operator">?</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>b<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token class-name">__</span><span class="token punctuation">.</span>prototype <span class="token operator">=</span> b<span class="token punctuation">.</span>prototype<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">__</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>不得不说这打包后的代码十分严谨，上面说的我的文章《面试官问：<code>JS</code>的继承》中没有提到不支持<code>__proto__</code>的情况。看来这文章可以进一步严谨修正了。
让我想起<code>Vue</code>源码中对数组检测代理判断是否支持<code>__proto__</code>的判断。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// vuejs 源码：https://github.com/vuejs/vue/blob/dev/dist/vue.js#L526-L527</span>
<span class="token comment">// can we use __proto__?</span>
<span class="token keyword">var</span> hasProto <span class="token operator">=</span> <span class="token string">'__proto__'</span> <span class="token keyword">in</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>看完打包代码实现的继承，继续看 <code>BrowserBackend</code> 构造函数</p> <h3 id="_6-3-browserbackend-构造函数-浏览器后端"><a href="#_6-3-browserbackend-构造函数-浏览器后端" class="header-anchor">#</a> 6.3 BrowserBackend  构造函数 （浏览器后端）</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> BrowserBackend <span class="token operator">=</span> <span class="token comment">/** @class */</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">_super</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">__extends</span><span class="token punctuation">(</span>BrowserBackend<span class="token punctuation">,</span> _super<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">function</span> <span class="token function">BrowserBackend</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> _super <span class="token operator">!==</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token function">_super</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">/**
	 * 设置请求
	 */</span>
	<span class="token class-name">BrowserBackend</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_setupTransport</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>_options<span class="token punctuation">.</span>dsn<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token comment">// We return the noop transport here in case there is no Dsn.</span>
			<span class="token comment">// 没有设置dsn，调用BaseBackend.prototype._setupTransport 返回空函数</span>
			<span class="token keyword">return</span> <span class="token class-name">_super</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">_setupTransport</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">var</span> transportOptions <span class="token operator">=</span> <span class="token function">__assign</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_options<span class="token punctuation">.</span>transportOptions<span class="token punctuation">,</span> <span class="token punctuation">{</span> dsn<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_options<span class="token punctuation">.</span>dsn <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>_options<span class="token punctuation">.</span>transport<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">this<span class="token punctuation">.</span>_options<span class="token punctuation">.</span>transport</span><span class="token punctuation">(</span>transportOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token comment">// 支持Fetch则返回 FetchTransport 实例，否则返回 XHRTransport实例，</span>
		<span class="token comment">// 这两个构造函数具体代码在开头已有提到。</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">supportsFetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">FetchTransport</span><span class="token punctuation">(</span>transportOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">XHRTransport</span><span class="token punctuation">(</span>transportOptions<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token comment">// code ...</span>
	<span class="token keyword">return</span> BrowserBackend<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">(</span>BaseBackend<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><code>BrowserBackend</code> 又继承自 <code>BaseBackend</code>。</p> <h4 id="_6-3-1-basebackend-构造函数-基础后端"><a href="#_6-3-1-basebackend-构造函数-基础后端" class="header-anchor">#</a> 6.3.1 BaseBackend  构造函数 （基础后端）</h4> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * This is the base implemention of a Backend.
 * @hidden
 */</span>
<span class="token keyword">var</span> BaseBackend <span class="token operator">=</span> <span class="token comment">/** @class */</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">/** Creates a new backend instance. */</span>
	<span class="token keyword">function</span> <span class="token function">BaseBackend</span><span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_options <span class="token operator">=</span> options<span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>_options<span class="token punctuation">.</span>dsn<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			logger<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">'No DSN provided, backend will not do anything.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token comment">// 调用设置请求函数</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_transport <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_setupTransport</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">/**
	 * Sets up the transport so it can be used later to send requests.
	 * 设置发送请求空函数
	 */</span>
	<span class="token class-name">BaseBackend</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_setupTransport</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">NoopTransport</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token comment">// code ...</span>
	<span class="token class-name">BaseBackend</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">sendEvent</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_transport<span class="token punctuation">.</span><span class="token function">sendEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">&quot;Error while sending event: &quot;</span> <span class="token operator">+</span> reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token class-name">BaseBackend</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">getTransport</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_transport<span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> BaseBackend<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>通过一系列的继承后，回过头来看 <code>BaseClient</code> 构造函数。</p> <h4 id="_6-3-2-baseclient-构造函数-基础客户端"><a href="#_6-3-2-baseclient-构造函数-基础客户端" class="header-anchor">#</a> 6.3.2 BaseClient 构造函数（基础客户端）</h4> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">var</span> BaseClient <span class="token operator">=</span> <span class="token comment">/** @class */</span> <span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">/**
	 * Initializes this client instance.
	 *
	 * @param backendClass A constructor function to create the backend.
	 * @param options Options for the client.
	 */</span>
	<span class="token keyword">function</span> <span class="token function">BaseClient</span><span class="token punctuation">(</span><span class="token parameter">backendClass<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token comment">/** Array of used integrations. */</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_integrations <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
		<span class="token comment">/** Is the client still processing a call? */</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_processing <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_backend <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">backendClass</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">this</span><span class="token punctuation">.</span>_options <span class="token operator">=</span> options<span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>dsn<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>_dsn <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dsn</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span>dsn<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_isEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>_integrations <span class="token operator">=</span> <span class="token function">setupIntegrations</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>_options<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// code ...</span>
	<span class="token keyword">return</span> BaseClient<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_6-4-小结1-new-browerclient-经过一系列的继承和初始化"><a href="#_6-4-小结1-new-browerclient-经过一系列的继承和初始化" class="header-anchor">#</a> 6.4 小结1. new BrowerClient 经过一系列的继承和初始化</h3> <p>可以输出下具体<code>new clientClass(options)</code>之后的结果：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">initAndBind</span><span class="token punctuation">(</span><span class="token parameter">clientClass<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>debug <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		logger<span class="token punctuation">.</span><span class="token function">enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">var</span> client <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">clientClass</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">;</span>
	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'new clientClass(options)'</span><span class="token punctuation">,</span> client<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">bindClient</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 原来的代码</span>
	<span class="token comment">// getCurrentHub().bindClient(new clientClass(options));</span>
<span class="token punctuation">}</span>
</code></pre></div><p>最终输出得到这样的数据。我画了一张图表示。重点关注的原型链用颜色标注了，其他部分收缩了。</p> <p><img src="/assets/img/BrowserClient-instance.e70bf588.png" alt="sentry new BrowserClient 实例图 By@若川"></p> <h2 id="_7-initandbind-函数之-getcurrenthub-bindclient"><a href="#_7-initandbind-函数之-getcurrenthub-bindclient" class="header-anchor">#</a> 7. initAndBind 函数之 getCurrentHub().bindClient()</h2> <p>继续看 <code>initAndBind</code> 的另一条线。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">initAndBind</span><span class="token punctuation">(</span><span class="token parameter">clientClass<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>debug <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		logger<span class="token punctuation">.</span><span class="token function">enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">bindClient</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">clientClass</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>获取当前的控制中心 <code>Hub</code>，再把<code>new BrowserClient()</code> 的实例对象绑定在<code>Hub</code>上。</p> <h3 id="_7-1-getcurrenthub-函数"><a href="#_7-1-getcurrenthub-函数" class="header-anchor">#</a> 7.1 getCurrentHub 函数</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 获取当前Hub 控制中心</span>
<span class="token keyword">function</span> <span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// Get main carrier (global for every environment)</span>
	<span class="token keyword">var</span> registry <span class="token operator">=</span> <span class="token function">getMainCarrier</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 如果没有控制中心在载体上，或者它的版本是老版本，就设置新的。</span>
	<span class="token comment">// If there's no hub, or its an old API, assign a new one</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">hasHubOnCarrier</span><span class="token punctuation">(</span>registry<span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token function">getHubFromCarrier</span><span class="token punctuation">(</span>registry<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isOlderThan</span><span class="token punctuation">(</span><span class="token constant">API_VERSION</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token function">setHubOnCarrier</span><span class="token punctuation">(</span>registry<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Hub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// node 才执行</span>
	<span class="token comment">// Prefer domains over global if they are there (applicable only to Node environment)</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isNodeEnv</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> <span class="token function">getHubFromActiveDomain</span><span class="token punctuation">(</span>registry<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 返回当前控制中心来自载体上。</span>
	<span class="token comment">// Return hub that lives on a global object</span>
	<span class="token keyword">return</span> <span class="token function">getHubFromCarrier</span><span class="token punctuation">(</span>registry<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="_7-2-衍生的函数-getmaincarrier、gethubfromcarrier"><a href="#_7-2-衍生的函数-getmaincarrier、gethubfromcarrier" class="header-anchor">#</a> 7.2 衍生的函数 getMainCarrier、getHubFromCarrier</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">getMainCarrier</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 载体 这里是window</span>
	<span class="token comment">// 通过一系列new BrowerClient() 一系列的初始化</span>
	<span class="token comment">// 挂载在  carrier.__SENTRY__ 已经有了三个属性，globalEventProcessors, hub, logger</span>
	<span class="token keyword">var</span> carrier <span class="token operator">=</span> <span class="token function">getGlobalObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	carrier<span class="token punctuation">.</span>__SENTRY__ <span class="token operator">=</span> carrier<span class="token punctuation">.</span>__SENTRY__ <span class="token operator">||</span> <span class="token punctuation">{</span>
		hub<span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> carrier<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 获取控制中心 hub 从载体上</span>
<span class="token keyword">function</span> <span class="token function">getHubFromCarrier</span><span class="token punctuation">(</span><span class="token parameter">carrier</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 已经有了则返回，没有则new Hub</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>carrier <span class="token operator">&amp;&amp;</span> carrier<span class="token punctuation">.</span>__SENTRY__ <span class="token operator">&amp;&amp;</span> carrier<span class="token punctuation">.</span>__SENTRY__<span class="token punctuation">.</span>hub<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span> carrier<span class="token punctuation">.</span>__SENTRY__<span class="token punctuation">.</span>hub<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	carrier<span class="token punctuation">.</span>__SENTRY__ <span class="token operator">=</span> carrier<span class="token punctuation">.</span>__SENTRY__ <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
	carrier<span class="token punctuation">.</span>__SENTRY__<span class="token punctuation">.</span>hub <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Hub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> carrier<span class="token punctuation">.</span>__SENTRY__<span class="token punctuation">.</span>hub<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="_7-3-bindclient-绑定客户端在当前控制中心上"><a href="#_7-3-bindclient-绑定客户端在当前控制中心上" class="header-anchor">#</a> 7.3 bindClient 绑定客户端在当前控制中心上</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">Hub</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">bindClient</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">client</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 获取最后一个</span>
	<span class="token keyword">var</span> top <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getStackTop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 把 new BrowerClient() 实例 绑定到top上</span>
	top<span class="token punctuation">.</span>client <span class="token operator">=</span> client<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">Hub</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">getStackTop</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 获取最后一个</span>
	<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_stack<span class="token punctuation">[</span><span class="token keyword">this</span><span class="token punctuation">.</span>_stack<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><h3 id="_7-4-小结2-经过一系列的继承和初始化"><a href="#_7-4-小结2-经过一系列的继承和初始化" class="header-anchor">#</a> 7.4 小结2. 经过一系列的继承和初始化</h3> <p>再回过头来看 <code>initAndBind</code>函数</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">initAndBind</span><span class="token punctuation">(</span><span class="token parameter">clientClass<span class="token punctuation">,</span> options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>options<span class="token punctuation">.</span>debug <span class="token operator">===</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		logger<span class="token punctuation">.</span><span class="token function">enable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">var</span> client <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">clientClass</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span><span class="token punctuation">;</span>
	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>client<span class="token punctuation">,</span> options<span class="token punctuation">,</span> <span class="token string">'client, options'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">var</span> currentHub <span class="token operator">=</span> <span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	currentHub<span class="token punctuation">.</span><span class="token function">bindClient</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span><span class="token punctuation">;</span>
	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'currentHub'</span><span class="token punctuation">,</span> currentHub<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 源代码</span>
	<span class="token comment">// getCurrentHub().bindClient(new clientClass(options));</span>
<span class="token punctuation">}</span>
</code></pre></div><p>最终会得到这样的<code>Hub</code>实例对象。笔者画了一张图表示，便于查看理解。</p> <p><img src="/assets/img/Hub-instance-new.3077372d.png" alt="Hub 实例关系图"></p> <p>初始化完成后，再来看具体例子。
具体 <code>captureMessage</code> 函数的实现。</p> <div class="language-js extra-class"><pre class="language-js"><code>Sentry<span class="token punctuation">.</span><span class="token function">captureMessage</span><span class="token punctuation">(</span><span class="token string">'Hello, 若川!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><h2 id="_8-capturemessage-函数"><a href="#_8-capturemessage-函数" class="header-anchor">#</a> 8. captureMessage 函数</h2> <p>通过之前的阅读代码，知道会最终会调用<code>Fetch</code>接口，所以直接断点调试即可，得出如下调用栈。
接下来描述调用栈的主要流程。</p> <p><img src="/assets/img/captureMessageCallStack.1714e9ff.png" alt="captureMessage 断点调试图"></p> <blockquote><p>调用栈主要流程：</p></blockquote> <p>captureMessage</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">captureMessage</span><span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> level</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> syntheticException<span class="token punctuation">;</span>
	<span class="token keyword">try</span> <span class="token punctuation">{</span>
		<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">catch</span> <span class="token punctuation">(</span>exception<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		syntheticException <span class="token operator">=</span> exception<span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 调用 callOnHub 方法</span>
	<span class="token keyword">return</span> <span class="token function">callOnHub</span><span class="token punctuation">(</span><span class="token string">'captureMessage'</span><span class="token punctuation">,</span> message<span class="token punctuation">,</span> level<span class="token punctuation">,</span> <span class="token punctuation">{</span>
		originalException<span class="token operator">:</span> message<span class="token punctuation">,</span>
		syntheticException<span class="token operator">:</span> syntheticException<span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>=&gt; callOnHub</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * This calls a function on the current hub.
 * @param method function to call on hub.
 * @param args to pass to function.
 */</span>
<span class="token keyword">function</span> <span class="token function">callOnHub</span><span class="token punctuation">(</span><span class="token parameter">method</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 这里method 传进来的是 'captureMessage'</span>
	<span class="token comment">// 把method除外的其他参数放到args数组中</span>
	<span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> _i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> _i <span class="token operator">&lt;</span> arguments<span class="token punctuation">.</span>length<span class="token punctuation">;</span> _i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		args<span class="token punctuation">[</span>_i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> arguments<span class="token punctuation">[</span>_i<span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token comment">// 获取当前控制中心 hub</span>
	<span class="token keyword">var</span> hub <span class="token operator">=</span> <span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 有这个方法 把args 数组展开，传递给 hub[method] 执行</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>hub <span class="token operator">&amp;&amp;</span> hub<span class="token punctuation">[</span>method<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token comment">// tslint:disable-next-line:no-unsafe-any</span>
		<span class="token keyword">return</span> hub<span class="token punctuation">[</span>method<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>hub<span class="token punctuation">,</span> <span class="token function">__spread</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">&quot;No hub defined or &quot;</span> <span class="token operator">+</span> method <span class="token operator">+</span> <span class="token string">&quot; was not found on the hub, please open a bug report.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>=&gt;  Hub.prototype.captureMessage</p> <p>接着看<code>Hub.prototype</code> 上定义的 <code>captureMessage</code> 方法</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">Hub</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">captureMessage</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> level<span class="token punctuation">,</span> hint</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> eventId <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>_lastEventId <span class="token operator">=</span> <span class="token function">uuid4</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">var</span> finalHint <span class="token operator">=</span> hint<span class="token punctuation">;</span>
	<span class="token comment">// 代码有删减</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_invokeClient</span><span class="token punctuation">(</span><span class="token string">'captureMessage'</span><span class="token punctuation">,</span> message<span class="token punctuation">,</span> level<span class="token punctuation">,</span> <span class="token function">__assign</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> finalHint<span class="token punctuation">,</span> <span class="token punctuation">{</span> event_id<span class="token operator">:</span> eventId <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span> eventId<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>=&gt; Hub.prototype._invokeClient</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">/**
 * Internal helper function to call a method on the top client if it exists.
 *
 * @param method The method to call on the client.
 * @param args Arguments to pass to the client function.
 */</span>
<span class="token class-name">Hub</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_invokeClient</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">method</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token comment">// 同样：这里method 传进来的是 'captureMessage'</span>
	<span class="token comment">// 把method除外的其他参数放到args数组中</span>
	<span class="token keyword">var</span> _a<span class="token punctuation">;</span>
	<span class="token keyword">var</span> args <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> _i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> _i <span class="token operator">&lt;</span> arguments<span class="token punctuation">.</span>length<span class="token punctuation">;</span> _i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		args<span class="token punctuation">[</span>_i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> arguments<span class="token punctuation">[</span>_i<span class="token punctuation">]</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">var</span> top <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getStackTop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token comment">// 获取控制中心的 hub，调用客户端也就是new BrowerClient () 实例中继承自 BaseClient 的 captureMessage 方法</span>
	<span class="token comment">// 有这个方法 把args 数组展开，传递给 hub[method] 执行</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span>top <span class="token operator">&amp;&amp;</span> top<span class="token punctuation">.</span>client <span class="token operator">&amp;&amp;</span> top<span class="token punctuation">.</span>client<span class="token punctuation">[</span>method<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token punctuation">(</span>_a <span class="token operator">=</span> top<span class="token punctuation">.</span>client<span class="token punctuation">)</span><span class="token punctuation">[</span>method<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span>_a<span class="token punctuation">,</span> <span class="token function">__spread</span><span class="token punctuation">(</span>args<span class="token punctuation">,</span> <span class="token punctuation">[</span>top<span class="token punctuation">.</span>scope<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>=&gt; BaseClient.prototype.captureMessage</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">BaseClient</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">captureMessage</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">message<span class="token punctuation">,</span> level<span class="token punctuation">,</span> hint<span class="token punctuation">,</span> scope</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> _this <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
	<span class="token keyword">var</span> eventId <span class="token operator">=</span> hint <span class="token operator">&amp;&amp;</span> hint<span class="token punctuation">.</span>event_id<span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_processing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
	<span class="token keyword">var</span> promisedEvent <span class="token operator">=</span> <span class="token function">isPrimitive</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span>
		<span class="token operator">?</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_getBackend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">eventFromMessage</span><span class="token punctuation">(</span><span class="token string">&quot;&quot;</span> <span class="token operator">+</span> message<span class="token punctuation">,</span> level<span class="token punctuation">,</span> hint<span class="token punctuation">)</span>
		<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_getBackend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">eventFromException</span><span class="token punctuation">(</span>message<span class="token punctuation">,</span> hint<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">// 代码有删减</span>
	promisedEvent
		<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> _this<span class="token punctuation">.</span><span class="token function">_processEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span> hint<span class="token punctuation">,</span> scope<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
	<span class="token comment">// 代码有删减</span>
	<span class="token keyword">return</span> eventId<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>最后会调用 <code>_processEvent</code> 也就是</p> <p>=&gt; BaseClient.prototype._processEvent</p> <p>这个函数最终会调用</p> <div class="language-js extra-class"><pre class="language-js"><code>_this<span class="token punctuation">.</span><span class="token function">_getBackend</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">sendEvent</span><span class="token punctuation">(</span>finalEvent<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>也就是</p> <p>=&gt;  BaseBackend.prototype.sendEvent</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">BaseBackend</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">sendEvent</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_transport<span class="token punctuation">.</span><span class="token function">sendEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">reason</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		logger<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">&quot;Error while sending event: &quot;</span> <span class="token operator">+</span> reason<span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>=&gt; FetchTransport.prototype.sendEvent 最终发送了请求</p> <h3 id="_8-1-fetchtransport-prototype-sendevent"><a href="#_8-1-fetchtransport-prototype-sendevent" class="header-anchor">#</a> 8.1 FetchTransport.prototype.sendEvent</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">FetchTransport</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">sendEvent</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">var</span> defaultOptions <span class="token operator">=</span> <span class="token punctuation">{</span>
		body<span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>event<span class="token punctuation">)</span><span class="token punctuation">,</span>
		method<span class="token operator">:</span> <span class="token string">'POST'</span><span class="token punctuation">,</span>
		<span class="token comment">// Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default</span>
		<span class="token comment">// https://caniuse.com/#feat=referrer-policy</span>
		<span class="token comment">// It doesn't. And it throw exception instead of ignoring this parameter...</span>
		<span class="token comment">// REF: https://github.com/getsentry/raven-js/issues/1233</span>
		referrerPolicy<span class="token operator">:</span> <span class="token punctuation">(</span><span class="token function">supportsReferrerPolicy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token string">'origin'</span> <span class="token operator">:</span> <span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token comment">// global$2.fetch(this.url, defaultOptions) 使用fetch发送请求</span>
	<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_buffer<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>global$<span class="token number">2.</span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>url<span class="token punctuation">,</span> defaultOptions<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
		status<span class="token operator">:</span> exports<span class="token punctuation">.</span>Status<span class="token punctuation">.</span><span class="token function">fromHttpCode</span><span class="token punctuation">(</span>response<span class="token punctuation">.</span>status<span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>看完 <code>Ajax 上报</code> 主线，再看本文的另外一条主线 <code>window.onerror</code> 捕获。</p> <h2 id="_9-window-onerror-和-window-onunhandledrejection-捕获-错误"><a href="#_9-window-onerror-和-window-onunhandledrejection-捕获-错误" class="header-anchor">#</a> 9. window.onerror 和 window.onunhandledrejection 捕获 错误</h2> <p>例子：调用一个未申明的变量。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p><code>Promise</code> 不捕获错误</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
	<span class="token function">fun</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'then'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><h3 id="_9-1-captureevent"><a href="#_9-1-captureevent" class="header-anchor">#</a> 9.1 captureEvent</h3> <blockquote><p>调用栈主要流程：</p></blockquote> <blockquote><p>window.onerror</p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">GlobalHandlers</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_installGlobalOnErrorHandler</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>_onErrorHandlerInstalled<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">var</span> self <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token comment">// tslint:disable-line:no-this-assignment</span>
	<span class="token comment">// 浏览器中这里的 this._global.  就是window</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_oldOnErrorHandler <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span>onerror<span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">msg<span class="token punctuation">,</span> url<span class="token punctuation">,</span> line<span class="token punctuation">,</span> column<span class="token punctuation">,</span> error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">var</span> currentHub <span class="token operator">=</span> <span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token comment">// 代码有删减</span>
		currentHub<span class="token punctuation">.</span><span class="token function">captureEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span> <span class="token punctuation">{</span>
			originalException<span class="token operator">:</span> error<span class="token punctuation">,</span>
		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>self<span class="token punctuation">.</span>_oldOnErrorHandler<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">return</span> self<span class="token punctuation">.</span><span class="token function">_oldOnErrorHandler</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_onErrorHandlerInstalled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><blockquote><p>window.onunhandledrejection</p></blockquote> <div class="language-js extra-class"><pre class="language-js"><code><span class="token class-name">GlobalHandlers</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">_installGlobalOnUnhandledRejectionHandler</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>_onUnhandledRejectionHandlerInstalled<span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token keyword">return</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
	<span class="token keyword">var</span> self <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span> <span class="token comment">// tslint:disable-line:no-this-assignment</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_oldOnUnhandledRejectionHandler <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span>onunhandledrejection<span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_global<span class="token punctuation">.</span><span class="token function-variable function">onunhandledrejection</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
		<span class="token comment">// 代码有删减</span>
		<span class="token keyword">var</span> currentHub <span class="token operator">=</span> <span class="token function">getCurrentHub</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		currentHub<span class="token punctuation">.</span><span class="token function">captureEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span> <span class="token punctuation">{</span>
			originalException<span class="token operator">:</span> error<span class="token punctuation">,</span>
		<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token keyword">if</span> <span class="token punctuation">(</span>self<span class="token punctuation">.</span>_oldOnUnhandledRejectionHandler<span class="token punctuation">)</span> <span class="token punctuation">{</span>
			<span class="token keyword">return</span> self<span class="token punctuation">.</span><span class="token function">_oldOnUnhandledRejectionHandler</span><span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> arguments<span class="token punctuation">)</span><span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span><span class="token punctuation">;</span>
	<span class="token keyword">this</span><span class="token punctuation">.</span>_onUnhandledRejectionHandlerInstalled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>共同点：都会调用<code>currentHub.captureEvent</code></p> <div class="language-js extra-class"><pre class="language-js"><code>currentHub<span class="token punctuation">.</span><span class="token function">captureEvent</span><span class="token punctuation">(</span>event<span class="token punctuation">,</span> <span class="token punctuation">{</span>
	originalException<span class="token operator">:</span> error<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>=&gt; Hub.prototype.captureEvent</p> <p>最终又是调用 <code>_invokeClient</code> ，调用流程跟 <code>captureMessage</code> 类似，这里就不再赘述。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_invokeClient</span><span class="token punctuation">(</span><span class="token string">'captureEvent'</span><span class="token punctuation">)</span>
</code></pre></div><p>=&gt; Hub.prototype._invokeClient</p> <p>=&gt; BaseClient.prototype.captureEvent</p> <p>=&gt; BaseClient.prototype._processEvent</p> <p>=&gt;  BaseBackend.prototype.sendEvent</p> <p>=&gt; FetchTransport.prototype.sendEvent</p> <p>最终同样是调用了这个函数发送了请求。</p> <p>可谓是殊途同归，行文至此就基本已经结束，最后总结一下。</p> <h2 id="_10-总结"><a href="#_10-总结" class="header-anchor">#</a> 10. 总结</h2> <p><code>Sentry-JavaScript</code>源码高效利用了<code>JS</code>的原型链机制。可谓是惊艳，值得学习。</p> <p>本文通过梳理前端错误监控知识、介绍<code>sentry</code>错误监控原理、<code>sentry</code>初始化、<code>Ajax</code>上报、<code>window.onerror、window.onunhandledrejection</code>几个方面来学习<code>sentry</code>的源码。还有很多细节和构造函数没有分析。</p> <p>总共的构造函数（类）有25个，提到的主要有9个，分别是：<code>Hub、BaseClient、BaseBackend、BaseTransport、FetchTransport、XHRTransport、BrowserBackend、BrowserClient、GlobalHandlers</code>。</p> <p>其他没有提到的分别是 <code>SentryError、Logger、Memo、SyncPromise、PromiseBuffer、Span、Scope、Dsn、API、NoopTransport、FunctionToString、InboundFilters、TryCatch、Breadcrumbs、LinkedErrors、UserAgent</code>。</p> <p>这些构造函数（类）中还有很多值得学习，比如同步的<code>Promise</code>（SyncPromise）。
有兴趣的读者，可以看这一块官方仓库中采用<code>typescript</code>写的源码<a href="https://github.com/getsentry/sentry-javascript/blob/master/packages/utils/src/syncpromise.ts" target="_blank" rel="noopener noreferrer">SyncPromise<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，也可以看打包后出来未压缩的代码。</p> <p>读源码比较耗费时间，写文章记录下来更加费时间（比如写这篇文章跨度十几天...），但收获一般都比较大。</p> <p>如果读者发现有不妥或可改善之处，再或者哪里没写明白的地方，欢迎评论指出。另外觉得写得不错，对您有些许帮助，可以点赞、评论、转发分享，也是对笔者的一种支持。万分感谢。</p> <h2 id="_11-推荐阅读"><a href="#_11-推荐阅读" class="header-anchor">#</a> 11. 推荐阅读</h2> <p><a href="https://zhuanlan.zhihu.com/p/51446011" target="_blank" rel="noopener noreferrer">知乎滴滴云：超详细！搭建一个前端错误监控系统<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5b7f63c96fb9a019f709b14b" target="_blank" rel="noopener noreferrer">掘金BlackHole1：JavaScript集成Sentry<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br>
丁香园 开源的<code>Sentry</code> 小程序 <code>SDK</code><a href="https://github.com/lizhiyao/sentry-miniapp" target="_blank" rel="noopener noreferrer">sentry-miniapp<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://sentry.io" target="_blank" rel="noopener noreferrer"><code>sentry</code>官网<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://github.com/getsentry/sentry-javascript" target="_blank" rel="noopener noreferrer"><code>sentry-javascript</code>仓库<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br></p> <h2 id="笔者往期文章"><a href="#笔者往期文章" class="header-anchor">#</a> 笔者往期文章</h2> <p><a href="https://juejin.im/post/5c433e216fb9a049c15f841b" target="_blank" rel="noopener noreferrer">面试官问：JS的继承<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5c0c87b35188252e8966c78a" target="_blank" rel="noopener noreferrer">面试官问：JS的this指向<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5bf6c79bf265da6142738b29" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的call和apply方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5bec4183f265da616b1044d7" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的bind方法<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5bde7c926fb9a049f66b8b52" target="_blank" rel="noopener noreferrer">面试官问：能否模拟实现JS的new操作符<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a><br> <a href="https://juejin.im/post/5b86732451882542af1c8082" target="_blank" rel="noopener noreferrer">前端使用puppeteer 爬虫生成《React.js 小书》PDF并合并<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <h2 id="关于"><a href="#关于" class="header-anchor">#</a> 关于</h2> <p>作者：常以<strong>若川</strong>为名混迹于江湖。前端路上 | PPT爱好者 | 所知甚少，唯善学。<br> <a href="https://lxchuan12.gitee.io" target="_blank" rel="noopener noreferrer">若川的博客<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，使用<code>vuepress</code>重构了，阅读体验可能更好些<br> <a href="https://juejin.im/user/1415826704971918/posts" target="_blank" rel="noopener noreferrer">掘金专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，欢迎关注~<br> <a href="https://segmentfault.com/blog/lxchuan12" target="_blank" rel="noopener noreferrer"><code>segmentfault</code>前端视野专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，欢迎关注~<br> <a href="https://zhuanlan.zhihu.com/lxchuan12" target="_blank" rel="noopener noreferrer">知乎前端视野专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，欢迎关注~<br> <a href="https://www.yuque.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer">语雀前端视野专栏<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，新增语雀专栏，欢迎关注~<br> <a href="https://github.com/lxchuan12/blog" target="_blank" rel="noopener noreferrer">github blog<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，相关源码和资源都放在这里，求个<code>star</code>^_^~</p> <h2 id="微信公众号-若川视野"><a href="#微信公众号-若川视野" class="header-anchor">#</a> 微信公众号  若川视野</h2> <p>可能比较有趣的微信公众号，长按扫码关注（<strong>回复pdf获取前端优质书籍pdf</strong>）。欢迎加笔者微信<code>ruochuan12</code>（注明来源，基本来者不拒），拉您进【前端视野交流群】，长期交流学习~</p> <p><img src="/assets/img/wechat-official-accounts-mini.d9491f62.png" alt="若川视野"></p></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">最后更新时间:</span> <span class="time">4/3/2021, 3:57:21 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/vuex/" class="prev">
        学习 vuex 源码整体架构，打造属于自己的状态管理库
      </a></span> <span class="next"><a href="/lodash/">
        学习 lodash  源码整体架构，打造属于自己的函数式编程类库
      </a>
      →
    </span></p></div> </main></div><div class="global-ui"><BackToTop></BackToTop><!----></div></div>
    <script src="/assets/js/app.9fbcafa6.js" defer></script><script src="/assets/js/2.33539d56.js" defer></script><script src="/assets/js/17.60b94fab.js" defer></script><script src="/assets/js/23.72249401.js" defer></script>
  </body>
</html>
